Ichandra2 - #587
Conversation
Greptile SummaryThe PR adds an authenticated Shopify connection page and backend OAuth flow, including a browser GET callback, signed shop-bound state, tenant ownership enforcement, connection status, and environment-derived redirects.
Confidence Score: 4/5The PR is not yet safe to merge because the configured production flow still sends Shopify callbacks to a loopback address. The callback resolver accepts Files Needing Attention: backend/integrations/shopify_routes.py and fly.toml
|
| Filename | Overview |
|---|---|
| backend/integrations/shopify_routes.py | Implements the Shopify OAuth and connection flow, but its public callback resolver still accepts the production deployment's loopback-only backend URL. |
| backend/main_api_app.py | Mounts the Shopify REST router independently so unrelated webhook import failures do not suppress these routes. |
| frontend-nextjs/next.config.js | Proxies Shopify API requests from the frontend server to the local backend process. |
| frontend-nextjs/pages/integrations/index.tsx | Adds Shopify to the integrations catalog. |
| frontend-nextjs/pages/integrations/shopify.tsx | Adds the authenticated Shopify connection and status interface. |
Sequence Diagram
sequenceDiagram
participant User as Merchant Browser
participant UI as ATOM Frontend
participant API as ATOM Backend
participant Shopify
User->>UI: Connect shop
UI->>API: GET /api/shopify/auth/url
API-->>UI: Shopify authorize URL + signed state
UI->>Shopify: Navigate to authorize URL
Shopify-->>User: Authorization approval
Shopify->>API: GET /api/shopify/auth/callback
API->>Shopify: Exchange authorization code
Shopify-->>API: Access token
API->>API: Enforce workspace ownership and persist store
API-->>UI: Redirect with connection result
Reviews (3): Last reviewed commit: "fix(shopify): one-time state + fail-clos..." | Re-trigger Greptile
- GET callback route for Shopify browser redirect (was POST-only -> 405) - callback URI derived from deployment config (ATOM_PUBLIC_URL etc.), not hardcoded localhost - signed OAuth state binds user+workspace; tampered state rejected - callback never reassigns a store owned by a different workspace (cross-tenant protection verified) - require SHOPIFY_API_KEY/SHOPIFY_API_SECRET
- OAuth state now binds user+workspace+shop with a random nonce and 10min expiry; blocks cross-shop replay of a previously issued state - state parsed on '|' separators so shop domains with dots don't break verification - _redirect_base_url fails closed (no loopback) unless SHOPIFY_DEV_LOOPBACK=1; public URL resolved from ATOM_PUBLIC_URL/ATOM_BASE_URL/PYTHON_BACKEND_URL/NEXT_PUBLIC_API_URL
Description
Type of Change
Testing
pytest)tsc --noEmit)Checklist